﻿<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html>
<!-- saved from url=(0033)http://research.microsoft.com/pex -->
<head><link rel="StyleSheet" href="er.common.css" type="text/css" /><script src="er.common.js" type="text/javascript"> </script><link rel="SHORTCUT ICON" href="favicon.ico" /><link rel="icon" href="favicon.ico" type="image/x-icon" /><title>C:\Users\AO\Documents\Visual Studio 2010\AutomaTones3\automatones\AutomaTones\AutomaTones\HW Sense Compute\ComputeLaunchpad.cs</title></head><body><div class="banner"></div><h2 id="top">C:\Users\AO\Documents\Visual Studio 2010\AutomaTones3\automatones\AutomaTones\AutomaTones\HW Sense Compute\ComputeLaunchpad.cs</h2><div class="toggle"><p class="copyright"><a class="usercodeundertestcovered">user code under test</a>, 
  <span class="usercodeundertestnotcovered">user code under test (not covered)</span>, 
  <a class="userortestcodecovered">user code or test</a>, 
  <span class="userortestcodenotcovered">user code or test (not covered)</span>,
  <span class="tagged">tagged</span></p><table><tr><th>Methods</th></tr><tr><th /></tr></table><div class="toggle"><a class="button" href="#ID0EL">first</a><pre class="coverage">using System;
using AutomaTones.Model.Automaton_Model;
using Midi;
using Microsoft.Pex.Framework;

namespace AutomaTones.HW_Sense_Compute {

    /// &lt;summary&gt;
    /// Computation on inputs from the Launchpad. Part of the Hardware, Sense, Compute pattern.
    /// &lt;/summary&gt;
    /// &lt;author&gt;Anders Bech Mellson, anbh@itu.dk&lt;/author&gt;
    [PexClass]
    partial class ComputeLaunchpad : ICompute
    {
        private int _x, _y;
        <span id="ID0EL"><a class="button" href="#top">top</a></span><a class="userortestcodecovered">private readonly State _state = new State();</a>
        private bool _settingState, _pushed, _inputGrid, _controlButtonPressed;
        public Action&lt;int,int&gt; LaunchpadEvent;
        public Action&lt;bool&gt; StateButtonEvent;
        public Action&lt;State&gt; StateChangeEvent;
        public Action OkButtonEvent,ClearButtonEvent;

        /// &lt;summary&gt;
        /// Looks at the incoming NoteOnMessage and computes what to do with it.
        /// &lt;/summary&gt;
        /// &lt;param name="mMsg"&gt;&lt;/param&gt;
        [PexMethod]
        public void Compute(NoteOnMessage mMsg) {
            EvaluateNoteOnMessage(mMsg);
            // Is the pad being released
            if (!_pushed)
            {
                // Is it a statechange button thats being released
                if (!_inputGrid) {
                    StateButtonEvent(false);
                    _settingState = false;
                }
                return;
            }
            // Is the pad a statechange pad
            if (!_inputGrid) {
                // Is a statechange pad already being pushed
                if (_settingState)
                    return;
                SetState(mMsg.Pitch);
                StateButtonEvent(true);
                _settingState = true;
            }
                // Is the pad a valid pad within the 8x8 inputgrid
            else {
                SetXandYfromPitch(mMsg.Pitch);
                LaunchpadEvent(_x,_y);
            }
        }

        /// &lt;summary&gt;
        /// Checks the incoming NoteOnMessage and sets the relevant booleans according to the input.
        /// &lt;/summary&gt;
        private void EvaluateNoteOnMessage(NoteOnMessage noteMsg)
        {
            switch (noteMsg.Velocity)
            {
                // Pad is pushed down on the Launchpad
                case 127:
                    _pushed = true;
                    break;
                // Pad is being released on the Launchpad
                case 0:
                    _pushed = false;
                    break;
            }
            // Pad is in the square 8x8 grid on the Launchpad
            if (ValidPad(noteMsg.Pitch))
                _inputGrid = true;
            // Pad is one of the round state change pad's on the right side of the Launchpad
            else if (!ValidPad(noteMsg.Pitch))
                _inputGrid = false;
        }

        /// &lt;summary&gt;
        /// If one of the toprow buttons are pushed it sends events based on the correct button.
        /// &lt;/summary&gt;
        [PexMethod]
        public void ControlButton(ControlChangeMessage cMsg) {
            _controlButtonPressed = !_controlButtonPressed;
            if (_controlButtonPressed)
                switch ((int)cMsg.Control) {
                    case 104:
                        OkButtonEvent();
                        break;
                    case 111:
                        ClearButtonEvent();
                        break;
                }
        }

        /// &lt;summary&gt;
        /// Takes a Pitch and sets the global values of x &amp; y in this class.
        /// The incoming pitch messages are in the range 1-120, some modulo math converts these incoming messages to x &amp; y.
        /// Row one sends: 0-7, Row two sends 16-23, Row three: 32-39, Row four: 48-55, Row five: 64-71, Row six: 80-87, Row seven: 96-103, Row eight: 112-119.
        /// &lt;/summary&gt;
        /// &lt;param name="pitch"&gt;A Pitch message from an incoming MIDI message.&lt;/param&gt;
        private void SetXandYfromPitch(Pitch pitch) {
            int point = (int)pitch;
            _x = (point % 8);
            _y = (point - _x) / 16;
        }

        /// &lt;summary&gt;
        /// Checks if the incoming pitch if within the valid range. Eg if the button press is within the 8x8 field of buttons.
        /// &lt;/summary&gt;
        /// &lt;param name="pitch"&gt;&lt;/param&gt;
        /// &lt;returns&gt;&lt;/returns&gt;
        private static bool ValidPad(Pitch pitch) {
            int p = (int)pitch;
            if (p &gt; 7 &amp;&amp; p &lt; 16 || p &gt; 23 &amp;&amp; p &lt; 32 || p &gt; 39 &amp;&amp; p &lt; 48 || p &gt; 55 &amp;&amp; p &lt; 64 || p &gt; 71 &amp;&amp; p &lt; 80 || p &gt; 87 &amp;&amp; p &lt; 96 || p &gt; 103 &amp;&amp; p &lt; 112 || p &gt; 119)
                return false;
            return true;
        }

        /// &lt;summary&gt;
        /// If the NoteOn message is not in the 8x8 button field, then sets the state according to the button pressed.
        /// &lt;/summary&gt;
        /// &lt;param name="pitch"&gt;&lt;/param&gt;
        private void SetState(Pitch pitch) {
            switch ((int) pitch) {
                case 8:
                    _state.CurrentState = 0;
                    break;
                case 24:
                    _state.CurrentState = 1;
                    break;
                case 40:
                    _state.CurrentState = 2;
                    break;
                case 56:
                    _state.CurrentState = 3;
                    break;
                case 72:
                    _state.CurrentState = 4;
                    break;
                case 88:
                    _state.CurrentState = 5;
                    break;
                case 104:
                    _state.CurrentState = 6;
                    break;
                case 120:
                    _state.CurrentState = 7;
                    break;
            }
            StateChangeEvent(_state);
        }
    }
}
</pre></div></div><hr /><table width="100%"><tr><td valign="top"><span class="copyright">Copyright (c) Microsoft Corporation. All rights reserved.</span><br /><span class="button" onclick="copySourceToClipboard()">Copy full source to clipboard</span></td></tr></table><div id="debugdiv"> </div></body></html>